package es.ucm.fdi.bdt;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Set;

import de.uniba.wiai.lspi.chord.service.ServiceException;
import es.ucm.fdi.bdt.commands.AvailableCommand;
import es.ucm.fdi.bdt.commands.BusyCommand;
import es.ucm.fdi.bdt.commands.ExitCommand;
import es.ucm.fdi.bdt.commands.TalkCommand;

public class ChatClient {
	
	protected final static int CLIENT_PORT = 55555;
	protected final static int MASTER_PORT = CLIENT_PORT;
	
	private String _username;
	private String _host;
	private boolean _isMaster = false;
	public static RegistrationInfo currentUser;
	
	public static void main(String[] args) throws ServiceException {
		new ChatClient().start(args);
	}

	private void start(String[] args) throws ServiceException {
		if (wrongNumberofArguments(args))
			printInstruction();

		setHostAndUsernameAndMasterStatus(args);
		ChordOverlayNetworkManager chordManager = new ChordOverlayNetworkManager(
				_isMaster, _host, MASTER_PORT);
		currentUser = createUser(chordManager);
		registerUser(currentUser, chordManager);
		startListening(chordManager);
		
		try {
			printCommands();
			
			System.out.println("host:" + currentUser.getHost() + "\n" + "port:"
					+ currentUser.getPort() + "\n" + "status:"
					+ currentUser.getStatus() + "\n" + "username:"
					+ currentUser.getUserName() + "\n");

			while (true) {
				System.out.println();
				System.out.print("> ");				
				
				String command = readCommand().toLowerCase();
				String[] commandParts = command.split(" ");
				String commandName = commandParts[0];

				if (commandName.equals("talk"))
					new TalkCommand(commandParts, chordManager, currentUser)
							.execute();
				else if (commandName.equals("read")) {
					Set<Serializable> msg = chordManager.recuperarMensaje();					
					if (!msg.isEmpty()){
						System.out.println("mensajes:"+
								Arrays.toString(msg.toArray(new Message[]{})));							
					} else {
						System.out.println("no hay mensajes.");
					}
				} else if (commandName.equals("busy"))
					new BusyCommand(currentUser, chordManager).execute();
				else if (commandName.equals("available"))
					new AvailableCommand(currentUser, chordManager).execute();
				else if (commandName.equals("activos"))
				    chordManager.mostrarUsuariosActivos();
				else if (commandName.equals("whoami"))
					System.out.println(currentUser.getUserName());
				else if (commandName.equals("exit"))
					new ExitCommand(currentUser, chordManager).execute();
				else
					System.out.println("Wrong Command, Retry!");
			}
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}

	private boolean wrongNumberofArguments(String[] args) {
		return args.length < 2 || args.length > 3;
	}
	
	private RegistrationInfo createUser(ChordOverlayNetworkManager chordManager) 
			throws ServiceException {
		
		RegistrationInfo user = new RegistrationInfo(_username, 
				ipExt(), 
				MASTER_PORT,
				true);
		
		return user;
	}
	
	private void registerUser(RegistrationInfo user, 
			ChordOverlayNetworkManager chordManager) 
			throws ServiceException {		
		if (!chordManager.register(user)) {
			System.err.println("The name '" + _username + "' is already taken!");
			System.exit(1);
		} else {
			System.err.println("The name '" + _username + "' registered!");			
		}		
	}

	private void startListening(ChordOverlayNetworkManager chordManager) 
			throws ServiceException {		
		MessageListener messageListener = new MessageListener();
		new Thread(messageListener).start();		
	}
	
	public static String ipExt() {
		try {
	        URL url = new URL("http://api.ipify.org");
	        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
	        BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
	        return rd.readLine();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}		
		try {
			return Inet4Address.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private static void printInstruction() {
		System.err
				.println("Usage:\n"
						+ "Start a master node\n"
						+ "java edu.gvsu.cis.cis656.lab3.ChatClient -master {user} {host}\n"
						+ "\n"
						+ "Start a regular node\n"
						+ "java edu.gvsu.cis.cis656.lab3.ChatClient {user} host:port\n");
		System.exit(1);
	}

	private void printCommands() {
		System.out.println("All Commands: ");
		System.out.println("* whoami");
		System.out.println("* talk [receiver] [message]");
		System.out.println("* busy");
		System.out.println("* read");
		System.out.println("* activos");
		System.out.println("* available");
		System.out.println("* exit");
	}

	private static String readCommand() {
		BufferedReader bufferedReader = new BufferedReader(
				new InputStreamReader(System.in));
		try {
			String input = bufferedReader.readLine();
			while (input.isEmpty())
				input = bufferedReader.readLine();
			return input;
		} catch (IOException e) {
			System.out.println("IO error trying to read command!");
			System.exit(1);
		}

		return "";
	}

	private void setHostAndUsernameAndMasterStatus(String[] args) {
		if (args[0].startsWith("-")) {
			_isMaster = true;
			_username = args[1].toLowerCase();
			_host = args[2];
		} else {
			_username = args[0].toLowerCase();
			_host = args[1];
		}
	}
}
